#ifndef STRING_H_
#define STRING_H_

template <int buffer_size>
class String
{
  public:
    String(void);
    ~String(void);
    String& operator= (char c);
    String& operator= (const char* s);
    template <int return_buffer_size> String& operator= (const String<return_buffer_size>& str);
    String& operator+= (char c);
    String& operator+= (const char* s);
    template <int return_buffer_size> String& operator+= (const String<return_buffer_size>& str);
    const char& operator[] (int pos) const;
    const char* c_str(void) const;
    int size(void) const;
    int capacity(void) const;
    bool full(void) const;
    template <int return_buffer_size> void substr(String<return_buffer_size> *str, int pos, int n) const;
    template <int return_buffer_size> void substr(String<return_buffer_size> *str, int pos) const;
    void clear(void);
    String& append(const char* s, int n);
    int compare (const char* s) const;
  
  private:
    int length;
    char buffer[buffer_size];
};

template <int buffer_size>
String<buffer_size>::String(void)
{
  length = 0;
}

template <int buffer_size>
String<buffer_size>::~String(void)
{
  free(buffer);
}

template <int buffer_size>
String<buffer_size>& String<buffer_size>::operator= (char c)
{
  buffer[0] = c;
  buffer[1] = 0;
  length = 1;
  return *this;
}

template <int buffer_size>
String<buffer_size>& String<buffer_size>::operator= (const char* s)
{
  int idx = 0;
  while (s[idx] != 0 && idx < buffer_size) {
    buffer[idx] = s[idx];
    idx++;
  }
  length = idx;
  buffer[length] = 0;
  return *this;
}

template <int buffer_size>
template <int return_buffer_size>
String<buffer_size>& String<buffer_size>::operator= (const String<return_buffer_size>& str)
{
  for (int idx = 0; idx < str.size() && idx < buffer_size; idx++) {
    buffer[idx] = str[idx];
  }
  length = str.size();
  if (length > buffer_size) {
    length = buffer_size;
  }
  buffer[length] = 0;
  return *this;
}

template <int buffer_size>
String<buffer_size>& String<buffer_size>::operator+= (char c)
{
  if (length < buffer_size) {
    buffer[length] = c;
    length++;
  }
  buffer[length] = 0;
  return *this;
}

template <int buffer_size>
String<buffer_size>& String<buffer_size>::operator+= (const char* s)
{
  int idx = 0;
  while (s[idx] != 0 && length + idx < buffer_size) {
    buffer[length + idx] = s[idx];
    idx++;
  }
  length = length + idx;
  buffer[length] = 0;
  return *this;
}

template <int buffer_size>
template <int return_buffer_size>
String<buffer_size>& String<buffer_size>::operator+= (const String<return_buffer_size>& str)
{
  for (int idx = 0; idx < str.size() && length + idx < buffer_size; idx++) {
    buffer[length + idx] = str[idx];
  }
  length = length + str.size();
  if (length > buffer_size) {
    length = buffer_size;
  }
  buffer[length] = 0;
  return *this;
}

template <int buffer_size>
const char& String<buffer_size>::operator[] (int pos) const
{
  return buffer[pos];
}

template <int buffer_size>
const char* String<buffer_size>::c_str(void) const
{
  return buffer;
}

template <int buffer_size>
int String<buffer_size>::size(void) const
{
  return length;
}

template <int buffer_size>
int String<buffer_size>::capacity(void) const
{
  return buffer_size;
}

template <int buffer_size>
bool String<buffer_size>::full(void) const
{
  return length == buffer_size - 1;  
}

template <int buffer_size>
template <int return_buffer_size>
void String<buffer_size>::substr(String<return_buffer_size> *str, int pos, int n) const
{
  str->clear();
  for (int idx = pos; idx < pos + n; idx++) {
    (*str) += buffer[idx];
  }
}

template <int buffer_size>
template <int return_buffer_size>
void String<buffer_size>::substr(String<return_buffer_size> *str, int pos) const
{
  substr(str, pos, length - pos);
}

template <int buffer_size>
void String<buffer_size>::clear(void)
{
  length = 0;
  buffer[length] = 0;
}

template <int buffer_size>
String<buffer_size>& String<buffer_size>::append(const char* s, int n)
{
  for (int idx = 0; idx < n && length + idx < buffer_size; idx++) {
    buffer[length + idx] = s[idx];
  }
  length = length + n;
  if (length > buffer_size) {
    length = buffer_size;
  }
  buffer[length] = 0;
  return *this;
}

template <int buffer_size>
int String<buffer_size>::compare(const char* s) const
{
  for (int idx = 0; idx < length; idx++) {
    if (s[idx] == 0) {
      return -1;
    }
    if (s[idx] != buffer[idx]) {
      return -1;
    }
  }
  return 0;
}


#endif /* STRING_H_ */
